/***********************************
* Name: BasicBlock.java
* Date: Oct 20, 2010
* @author martin
* Description:
***********************************/

package asmCodeGen;
import interCodeGen.*;
import java.util.LinkedList;


public class BasicBlock {
    
    private LinkedList<Cod3Dir> cod3dir = new LinkedList<Cod3Dir>();
    private LinkedList<AsmCode> asmCode = new LinkedList<AsmCode>();

    //********************
    //DI ya tiene a SP
    //********************

    public BasicBlock(LinkedList<Cod3Dir> cod3dir){
        this.cod3dir = cod3dir;
    }


    /***********************************
     * addToCode
     * @param code to add
     ***********************************/
    public void addToCode(AsmCode line){
        this.asmCode.add(line);
    }

    /*****************************************
     * @return the asmCode
     *****************************************/
    public LinkedList<AsmCode> getAsmCode() {
        return asmCode;
    }

    /*****************************************
     * generate
     *****************************************/
    public void generate() {

        for(Cod3Dir a : this.cod3dir){

            if(a instanceof interCodeGen.InterAsignacion){
                generateAsignacion((interCodeGen.InterAsignacion)a);
            }
            else if(a instanceof interCodeGen.InterComentario){
                generateComentario((interCodeGen.InterComentario)a);
            }
            else if(a instanceof interCodeGen.InterCondicional){
                generateCondicional((interCodeGen.InterCondicional)a);
            }
            else if(a instanceof interCodeGen.InterEtiqueta){
                generateEtiqueta((interCodeGen.InterEtiqueta)a);
            }
            else if(a instanceof interCodeGen.InterMethodCall){
                generateMethodCall((interCodeGen.InterMethodCall)a);
            }
            else if(a instanceof interCodeGen.InterOperacionBinaria){
                generateOperacionBinaria((interCodeGen.InterOperacionBinaria)a);
            }
            else if(a instanceof interCodeGen.InterOperacionUnaria){
                generateOperacionUnaria((interCodeGen.InterOperacionUnaria)a);
            }
            else if(a instanceof interCodeGen.InterParam){
                generateParam((interCodeGen.InterParam)a);
            }
            else if(a instanceof interCodeGen.InterPlane){
                generatePlane((interCodeGen.InterPlane)a);
            }
            else if(a instanceof interCodeGen.InterReturn){
                generateReturn((interCodeGen.InterReturn)a);
            }
            else if(a instanceof interCodeGen.InterSalto){
                generateSalto((interCodeGen.InterSalto)a);
            }

        }


    }

    /*****************************************
     * toString
     *****************************************/
    public String toString(){
        String retorno="";
        for(Cod3Dir a : this.cod3dir){
            retorno+=a.getCodeString()+"\n";
        }
        return retorno;
    }
    
    /*****************************************
     * generateSalto
     * generate a jump in assembler
     *****************************************/
    private void generateSalto(InterSalto interSalto) {
        this.addToCode(new CodeJump("JUMP",interSalto.getEtiqueta()));
    }

    /*****************************************
     * generateReturn
     * save in the correct direction
     *****************************************/
    private void generateReturn(InterReturn interReturn) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /*****************************************
     * generatePlane
     * copy the instruction
     *****************************************/
    private void generatePlane(InterPlane interPlane) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /*****************************************
     * generateAsignacion
     * generates the moves for an assign
     *****************************************/
    private void generateAsignacion(InterAsignacion interAsignacion) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /*****************************************
     * generateComentario
     * copy the comment
     *****************************************/
    private void generateComentario(InterComentario interComentario) {
        this.addToCode(new CodeComment(interComentario.getComentario()));
    }

    /*****************************************
     * generateCondicional
     * generate the instructions for a conditional
     *****************************************/
    private void generateCondicional(InterCondicional interCondicional) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /*****************************************
     * generateEtiqueta
     * copy the label
     *****************************************/
    private void generateEtiqueta(InterEtiqueta interEtiqueta) {
        this.addToCode(new CodeLabel(interEtiqueta.getEtiqueta()));
    }

    /*****************************************
     * generateMethodCall
     * generate the instructions for a methodCall
     *****************************************/
    private void generateMethodCall(InterMethodCall interMethodCall) {
        boolean isVoid = interMethodCall.isVoid_type();

        if(isVoid){

            this.addToCode(new CodeOperacionUnaria("CALL",interMethodCall.getNombre_funcion()));

        }else{

            String t1 = interMethodCall.getTemp_retorno();

            this.addToCode(new CodeOperacionUnaria("CALL",interMethodCall.getNombre_funcion()));
            this.addToCode(new CodeOperacionUnaria("POP","DX",true,"return value"));
            //TODO calcular la direccion de BX para donde guardarlo
            this.addToCode(new CodeOperacionBinaria("MOV","BX","direccion de "+t1));
            this.addToCode(new CodeOperacionBinaria("MOV","[SS:DI+BX]","DX"));

        }

    }

    /*****************************************
     * generateOperacionBinaria
     * generate the instructions for a binary operation
     *****************************************/
    private void generateOperacionBinaria(InterOperacionBinaria interOperacionBinaria) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /*****************************************
     * generateOperacionUnaria
     * generate the instructions for a operation
     *****************************************/
    private void generateOperacionUnaria(InterOperacionUnaria interOperacionUnaria) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /*****************************************
     * generateParam
     * generate the instructions for a parameter
     * generate also if needs all the push
     *****************************************/
    private void generateParam(InterParam interParam) {

        String method_subname_to_call = interParam.getFrom_funtion();
        int num = interParam.getNum_of_parameter();

        String t1 = interParam.getParam();

        if(num == 1){
            //es el primer parámetro, entonces hay que hacer varios push para alocar espacio
            //TODO está incompleto.. completar

        }

        if(isTemporal(t1)){

            //NO es literal.. es un temporal
            //TODO está incompleto.. completar
            //pasar del temporal a un registro
            this.addToCode(new CodeOperacionBinaria("MOV","BX","direccion del temporal"));
            this.addToCode(new CodeOperacionBinaria("MOV","DX","[SS:DI+BX]"));
            //hacer push del registro
            this.addToCode(new CodeOperacionUnaria("PUSH","DX",true,"param temporal - "+method_subname_to_call+" "+num));

        }
        else{

            //es un literal
            this.addToCode(new CodeOperacionUnaria("PUSH",t1,true,"param literal - "+method_subname_to_call+" "+num));

        }
    }


    private boolean isTemporal(String temp){
        return MethodInterCodeGen.isTemporal(temp);
    }
    
}
